package com.qijian.maindata.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.qijian.common.exception.ServiceException;
import com.qijian.common.utils.ObjectUtils;
import com.qijian.common.utils.StringUtils;
import com.qijian.common.utils.mybatis.WhereEntityTool;
import com.qijian.common.utils.uuid.IdUtils;
import com.qijian.maindata.domain.CommonClassify;
import com.qijian.maindata.domain.query.CommonClassifyQuery;
import com.qijian.maindata.service.ICommonClassifyService;
import com.qijian.tool.domain.Storage;
import com.qijian.maindata.domain.vo.CommonClassifyVo;
import com.qijian.maindata.mapper.CommonClassifyMapper;
import com.qijian.tool.service.IStorageService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 通用树形分类Service业务层处理
 *
 * @author qijian
 * @date 2021-12-23
 */
@Service
@RequiredArgsConstructor
public class CommonClassifyServiceImpl extends ServiceImpl<CommonClassifyMapper, CommonClassify> implements ICommonClassifyService {

    private final CommonClassifyMapper commonClassifyMapper;
    private final IStorageService storageService;

    @Override
    public List<CommonClassifyVo> listVo(CommonClassifyQuery query) {
        QueryWrapper<CommonClassify> wrapper = WhereEntityTool.invoke(query);
        wrapper.orderByAsc(Lists.newArrayList("top_classify_id", "parent_classify_id", "id"));
        List<CommonClassify> list = commonClassifyMapper.selectListVo(wrapper);
        List<CommonClassifyVo> result = new ArrayList<>();
        Iterator<CommonClassify> it = list.iterator();
        while (it.hasNext()) {
            CommonClassify s = it.next();
            CommonClassifyVo vo = new CommonClassifyVo();
            BeanUtils.copyProperties(s, vo);
            it.remove();
            findChildren(list, vo, result);
            //避免双迭代器导致的数据不一致，在此处重新获取一次迭代器，因为每次循环都会remove掉数据，所以没有影响
            it = list.iterator();
            result.add(vo);
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveDetail(CommonClassify commonClassify) {
        //清空祖级，由代码决定
        commonClassify.setAncestors(null);
        boolean isAdd = ObjectUtils.isNull(commonClassify.getId());
        if ("knifeArea".equals(commonClassify.getClassifyType()) && isAdd) {
            QueryWrapper<CommonClassify> queryWrapper = new QueryWrapper<CommonClassify>().eq("classify_type", "knifeArea").eq("parent_classify_id", commonClassify.getParentClassifyId());
            long count = this.list(queryWrapper).stream().filter(e -> e.getCode().equals(commonClassify.getCode())).count();
            if (count > 0) {
                throw new ServiceException("E01: 存在相同的编码" + commonClassify.getCode());
            }
        }
        if (commonClassify.getParentClassifyId() == null)
            commonClassify.setParentClassifyId(0L);
        boolean isTop = commonClassify.getParentClassifyId().equals(0L);
        //设置祖级
        if (isTop) {
            if (isAdd) {
                commonClassify.setId(IdUtils.singletonSnowId());
            }
            commonClassify.setAncestors("");
            commonClassify.setTopClassifyId(commonClassify.getId());
        }
        if (isAdd) {
            if (!isTop) {
                //获取父级的祖级，拼接parentId
                CommonClassify parent = this.getById(commonClassify.getParentClassifyId());
//                String ancestors = (StringUtils.isBlank(parent.getAncestors()) ? "" : parent.getAncestors() + ",") + commonClassify.getParentClassifyId();
                String ancestors = joinAncestors(parent, String.valueOf(commonClassify.getParentClassifyId()));
                commonClassify.setAncestors(ancestors);
            }
        } else {
            //获取老数据，看看parentId有没有变动，如果变动了，就需要更新自己和所有子孙级的祖级列表
            CommonClassify old = this.getById(commonClassify.getId());
            if (!old.getParentClassifyId().equals(commonClassify.getParentClassifyId())) {
                if (!isTop) {
                    Assert.isTrue(!commonClassify.getParentClassifyId().equals(commonClassify.getId()), "无法设置自己为父类！");
                    //获取父级的祖级，拼接parentId
                    CommonClassify parent = this.getById(commonClassify.getParentClassifyId());
//                    String ancestors = (StringUtils.isBlank(parent.getAncestors()) ? "" : parent.getAncestors() + ",") + commonClassify.getParentClassifyId();
                    String ancestors = joinAncestors(parent, String.valueOf(commonClassify.getParentClassifyId()));
                    commonClassify.setAncestors(ancestors);
                    commonClassify.setTopClassifyId(parent.getTopClassifyId());
                }
                CommonClassifyQuery q = new CommonClassifyQuery();
                q.setAncestorsLikeRight(joinAncestors(old, String.valueOf(old.getId())));
                List<CommonClassify> descendant = this.list(WhereEntityTool.invoke(q));


                descendant.forEach(c -> {
                    Assert.isTrue(!commonClassify.getParentClassifyId().equals(c.getId()), "无法设置自己的子类为父类！");
                    c.setAncestors(joinAncestors(commonClassify, String.valueOf(old.getId()), c.getAncestors().substring(q.getAncestorsLikeRight().length())));
                });
                this.updateBatchById(descendant);
            }
        }
        this.saveOrUpdate(commonClassify);
        // 文件来源更新
        if (ObjectUtils.isNotEmpty(commonClassify.getFiles())) {
            boolean canUpdate = true;
            if (!isAdd) {
                canUpdate = storageService.remove(Collections.singletonList(commonClassify.getId()), Collections.singletonList(commonClassify.getFiles().getStorageId()));
            }
            if (canUpdate) {
                Storage storage = new Storage();
                storage.setStorageId(commonClassify.getFiles().getStorageId());
                storage.setClassTable(CommonClassify.class.getSimpleName());
                storage.setClassId(commonClassify.getId());
                storageService.updateById(storage);
            }
        }
        return true;
    }

    @Override
    public List<CommonClassify> listByType(String type) {
        if (ObjectUtils.isNull(true)) return new ArrayList<>();
        CommonClassify q = new CommonClassify();
        q.setClassifyType(type);
        return this.list(new QueryWrapper<>(q));
    }

    @Override
    public void updateIdById(Long old, Long newestId) {
        commonClassifyMapper.updateIdById(old, newestId);
    }

    private String joinAncestors(CommonClassify pre, String... suffix) {
        StringBuilder result = new StringBuilder();
        if (pre != null && StringUtils.isNotBlank(pre.getAncestors()))
            joinAncestors(result, pre.getAncestors());
        for (String s : suffix) {
            if (StringUtils.isNotBlank(s))
                joinAncestors(result, s);
        }
        return result.toString();
    }

    private void joinAncestors(StringBuilder builder, String appendStr) {
        if (StringUtils.isNotBlank(appendStr)) {
            if (builder.length() > 0 && !appendStr.startsWith(","))
                builder.append(",");
            builder.append(appendStr);
        }
    }

    private void findChildren(List<CommonClassify> list, CommonClassifyVo classify, List<CommonClassifyVo> result) {
        List<CommonClassify> temp = Lists.newArrayList(list);
        Iterator<CommonClassify> it = temp.iterator();
        while (it.hasNext()) {
            CommonClassify s = it.next();
            if (classify.getId().equals(s.getParentClassifyId())) {
                list.remove(s);
                CommonClassifyVo vo = new CommonClassifyVo();
                BeanUtils.copyProperties(s, vo);
                it.remove();
                findChildren(list, vo, result);
                temp = Lists.newArrayList(list);
                it = temp.iterator();
                vo.setParentName(classify.getName());
                classify.addChildren(vo);
            }
        }
        Iterator<CommonClassifyVo> resultIt = result.iterator();
        while (resultIt.hasNext()) {
            CommonClassifyVo vo = resultIt.next();
            if (classify.getId().equals(vo.getParentClassifyId())) {
                vo.setParentName(classify.getName());
                classify.addChildren(vo);
                resultIt.remove();
            }
        }
    }

    @Override
    public CommonClassify getParentName(Long id) {
        return baseMapper.getParentName(id);
    }

    @Override
    public Map<Long, String> getParentName(List<Long> ids) {
        List<CommonClassify> classifyList = baseMapper.getParentNameByIds(ids);
        return classifyList.stream().collect(Collectors.toMap(CommonClassify::getId,CommonClassify::getName));
    }
}
